package ecomp.models;
import java.awt.Color;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class Cell {
	public static final Cell ZERO = new Cell(0,0,0);

	public int x, y;
	public int value;

	private boolean enemyAgent, allyAgent, cow, enemyCorral, allyCorral, fence,
	open, button, obstacle;
	private int timestamp, marked;
	private int cowId= -1;

	public int edgeValue = 0;

	public static final int UNMARKED = -1;
	public static final int RED_CROSS = 0;
	public static final int BLACK_CROSS = 1;
	public static final int MAGENTA_CIRCLE = 2;
	public static final int BLUE_CIRCLE = 3;

	private Color clusterColor;

	public Color getClusterColor ()
	{
		return clusterColor;
	}

	public void setClusterColor (Color clusterColor)
	{
		this.clusterColor = clusterColor;
	}

	public int getX(){
		return this.x;
	}

	public int getY(){
		return this.y;
	}

	public Cell(int x, int y, int step) {
		this.timestamp = step;
		this.marked = UNMARKED;
	}

	public static Cell create(Element elem, int posx, int posy, int step) {
		int x, y;
		try {
			x = Integer.parseInt(elem.getAttribute("x"));
			y = Integer.parseInt(elem.getAttribute("y"));
		} catch (Exception e) {
			return null;
		}
		Cell cell = new Cell(posx + x, posy + y, step);

		NodeList cellContents = elem.getElementsByTagName("*");

		for (int i = 0; i < cellContents.getLength(); i++) {
			Element cellContent = (Element) cellContents.item(i);
			String tagName = cellContent.getTagName();

			if (tagName.equalsIgnoreCase("empty")) {
				// nop
			} else if (tagName.equalsIgnoreCase("obstacle")) {
				cell.obstacle = true;
			} else if (tagName.equalsIgnoreCase("cow")) {
				cell.cowId = Integer.parseInt(cellContent.getAttribute("ID"));
				cell.cow = true;
			} else if (tagName.equalsIgnoreCase("corral")) {
				if (cellContent.getAttribute("type").equalsIgnoreCase("enemy")) {
					cell.enemyCorral = true;
				} else {
					cell.allyCorral = true;
				}
			} else if (tagName.equalsIgnoreCase("agent")) {
				if (cellContent.getAttribute("type").equals("ally")) {
					cell.allyAgent = true;
				} else {
					cell.enemyAgent = true;
				}
			} else if (tagName.equalsIgnoreCase("switch")) {
				cell.button = true;
			} else if (tagName.equalsIgnoreCase("unknown")) {
				return null;
			} else if (tagName.equalsIgnoreCase("fence")) {
				if (cellContent.getAttribute("open").equalsIgnoreCase("false")) {
					cell.fence = true;
					cell.open = false;
				} else {
					cell.fence = true;
					cell.open = true;
				}
			} else {
				System.err.println(("error... unknown perception..."));
				int attributecount = cellContent.getAttributes().getLength();
				System.err.print("attributcount: " + attributecount + ", ");
				System.err.println("tempName: " + tagName);
				System.err.println("tempName: " + tagName + ", attributcount: "
						+ attributecount + " ");
				for (int j = 0; i < attributecount; j++) {
					String attribute = cellContent.getAttributes().item(j)
							.getNodeName();
					System.err.print("AttributValue: "
							+ cellContent.getAttribute(attribute) + ", ");
					System.err.print("AttributName " + i + ": " + attribute
							+ " ");
				}
			}
		}
		return cell;
	}

	/**
	 * @return the cowId
	 */
	public Integer getCowId() {
		return cowId;
	}

	/**
	 * @return the enemyAgent
	 */
	public boolean isEnemyAgent() {
		return enemyAgent;
	}

	/**
	 * @param enemyAgent
	 *            the enemyAgent to set
	 */
	public void setEnemyAgent(boolean enemyAgent) {
		this.enemyAgent = enemyAgent;
	}

	/**
	 * @return the allyAgent
	 */
	public boolean isAllyAgent() {
		return allyAgent;
	}

	/**
	 * @param allyAgent
	 *            the allyAgent to set
	 */
	public void setAllyAgent(boolean allyAgent) {
		this.allyAgent = allyAgent;
	}

	/**
	 * @return the cow
	 */
	public boolean isCow() {
		return cow;
	}

	/**
	 * @param cow
	 *            the cow to set
	 */
	public void setCow(boolean cow) {
		this.cow = cow;
	}

	/**
	 * @return the enemyCorral
	 */
	public boolean isEnemyCorral() {
		return enemyCorral;
	}

	/**
	 * @param enemyCorral
	 *            the enemyCorral to set
	 */
	public void setEnemyCorral(boolean enemyCorral) {
		this.enemyCorral = enemyCorral;
	}

	/**
	 * @return the allyCorral
	 */
	public boolean isAllyCorral() {
		return allyCorral;
	}

	/**
	 * @param allyCorral
	 *            the allyCorral to set
	 */
	public void setAllyCorral(boolean allyCorral) {
		this.allyCorral = allyCorral;
	}

	/**
	 * @return the fence
	 */
	public boolean isFence() {
		return fence;
	}

	/**
	 * @param fence
	 *            the fence to set
	 */
	public void setFence(boolean fence) {
		this.fence = fence;
	}

	/**
	 * @return the open
	 */
	public boolean isOpen() {
		return open;
	}

	/**
	 * @param open
	 *            the open to set
	 */
	public void setOpen(boolean open) {
		this.open = open;
	}

	/**
	 * @return the empty
	 */
	public boolean isEmpty() {
		return !(enemyAgent || allyAgent || cow || enemyCorral || allyCorral
				|| fence || button || obstacle);
	}

	/**
	 * @return the button
	 */
	public boolean isSwitch() {
		return button;
	}

	/**
	 * @param button
	 *            the button to set
	 */
	public void setSwitch(boolean button) {
		this.button = button;
	}

	/**
	 * @return the obstacle
	 */
	public boolean isObstacle() {
		return obstacle || workaroundServerBug();
	}

	/**
	 * @param obstacle
	 *            the obstacle to set
	 */
	public void setObstacle(boolean obstacle) {
		this.obstacle = obstacle;
	}

	/**
	 * @return the marked
	 */
	public int getMarked ()
	{
		return marked;
	}

	/**
	 * @param marked the marked to set
	 */
	public void setMarked (int marked)
	{
		this.marked = marked;
	}

	/**
	 * @return the timestamp
	 */
	public int getTimestamp() {
		return timestamp;
	}

	/**
	 * @param timestamp
	 *            the timestamp to set
	 */
	public void setTimestamp(int timestamp) {
		this.timestamp = timestamp;
	}

	public boolean isUnknown() {
		return timestamp == -1;
	}

	public boolean isAccessible() {
		return isEmpty()
				|| (((fence && open) || allyCorral || enemyCorral) && !cow
						&& !allyAgent && !enemyAgent);
	}

	//return true if cell is bad
	public boolean workaroundServerBug()
	{
		return false;
		/*if(!isFence())
			return false;

		ArrayList<Cell> list = WorldModel.staticWorldModel.getNeighbours4(this.x, this.y);
		boolean isNextToSwitch = false;

		/*for (Cell cell : list)
		{
			if (cell.isSwitch())
			{
				isNextToSwitch = true;
				break;
			}
		}
		if (isFence() && isNextToSwitch)
		{
			marked = 3;
		}
		return isFence() && isNextToSwitch;*/
	}


	public String toString() {
		String cellInfo = "";
		cellInfo += "cell(" + x + ", " + y + ") is/has ";

		if (isEmpty()) {
			cellInfo += ("empty.");
		} else if (isObstacle()) {
			cellInfo += ("an obstacle.");
		} else if (isCow()) {
			cellInfo += ("cow with ID=" + cowId + ".");
		} else if (isEnemyCorral()) {
			cellInfo += ("enemy corral.");
		} else if (isAllyCorral()) {
			cellInfo += ("own corral.");
		} else if (isAllyAgent()) {
			cellInfo += ("an ally agent.");
		} else if (isEnemyAgent()) {
			cellInfo += ("an enemy agent.");
		} else if (isSwitch()) {
			cellInfo += ("switch.");
		} else if (isUnknown()) {
			cellInfo += ("unknown.");
		} else if (isFence()) {
			if (isOpen()) {
				cellInfo += ("open fence.");
			} else {
				cellInfo += ("closed fence.");
			}
		} else {
		}
		return cellInfo;
	}

	public String postionToSting ()
	{
		return  x + "," + y;
	}

	public String toStringShort() {
		String cellInfo = "";
		cellInfo += "(" + x + ", " + y + ")";
		return cellInfo;
	}

	public int maxNorm(Cell p)
    {
        return Math.max(Math.abs(this.x - p.x), Math.abs(this.y - p.y));
    }
    
    public double euklNorm(Cell p)
    {
        int a = this.x - p.x;
        int b = this.y - p.y;
        return Math.sqrt(a*a + b*b);
    }
    
    public double euklScalarProduct(Cell p)
    {
        return this.x*p.x+this.y*p.y;
    }
    
    public static int maxNorm(Cell p1, Cell p2)
    {
        return p1.maxNorm(p2);
    }

    public static double euklNorm(Cell p1, Cell p2)
    {
        return p1.euklNorm(p2);
    }

    public boolean equals(Object obj)
    {
        if(obj instanceof Cell)
        {
            Cell p = (Cell) obj;
            if(p.x == this.x && p.y == this.y)
                return true;
        }
        return false;
    }

        public int hashCode()
        {
                return x*10000+y;
        }
    
	
	public Cell clone() {
		Cell cell = new Cell(x,y,timestamp);
		cell.setAllyAgent(allyAgent);
		cell.setAllyCorral(allyCorral);
		cell.setCow(cow);
		cell.setEnemyAgent(enemyAgent);
		cell.setEnemyCorral(enemyCorral);
		cell.setFence(fence);
		cell.setObstacle(obstacle);
		cell.setOpen(open);
		cell.setSwitch(button);
		cell.value = value;
		return cell;
	}
}